home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 001a / mskrmsrc.zip / MSNICM.C < prev    next >
C/C++ Source or Header  |  1991-10-24  |  7KB  |  301 lines

  1. /* File MSNICM.C
  2.  * ICMP packet processor
  3.  *
  4.  * Copyright (C) 1991, University of Waterloo.
  5.  * Copyright (C) 1991, Trustees of Columbia University in the
  6.  *  City of New York.  Permission is granted to any individual or
  7.  *  institution to use, copy, or redistribute this software as long as
  8.  *  it is not sold for profit and this copyright notice is retained.
  9.  *
  10.  * Original version created by Erick Engelke of the University of
  11.  *  Waterloo, Waterloo, Ontario, Canada.
  12.  * Adapted and modified for MS-DOS Kermit by Joe R. Doupnik, 
  13.  *  Utah State University, jrd@cc.usu.edu, jrd@usu.Bitnet.
  14.  *
  15.  * Last edit
  16.  * 6 Sept 1991
  17.  */
  18. #include "msntcp.h"
  19. #include "msnlib.h"
  20.  
  21. /*
  22.  * ICMP - RFC 792
  23.  */
  24.  
  25. static byte *unreach[] = {
  26.     "Network Unreachable",
  27.     "Host Unreachable",
  28.     "Protocol Unreachable",
  29.     "Port Unreachable",
  30.     "Fragmentation needed and DF set",
  31.     "Source Route Failed" };
  32.  
  33. static byte *exceed[] = {
  34.     "TTL exceeded in transit",
  35.     "Frag ReAsm time exceeded" };
  36.  
  37. static byte *redirect[] = {
  38.     "Redirect for Network",
  39.     "Redirect for Host",
  40.     "Redirect for TOS and Network",
  41.     "Redirect for TOS and Host" };
  42.  
  43. /* constants */
  44.  
  45.  
  46. typedef struct icmp_unused {
  47.     byte     type;
  48.     byte    code;
  49.     word    checksum;
  50.     longword    unused;
  51.     in_Header    ip;
  52.     byte    spares[ 8 ];
  53. };
  54.  
  55. typedef struct icmp_pointer {
  56.     byte    type;
  57.     byte    code;
  58.     word    checksum;
  59.     byte    pointer;
  60.     byte    unused[ 3 ];
  61.     in_Header    ip;
  62. };
  63. typedef struct icmp_ip {
  64.     byte    type;
  65.     byte    code;
  66.     word    checksum;
  67.     longword    ipaddr;
  68.     in_Header    ip;
  69. };
  70. typedef struct icmp_echo {
  71.     byte    type;
  72.     byte    code;
  73.     word    checksum;
  74.     word    identifier;
  75.     word    sequence;
  76. };
  77.  
  78. typedef struct icmp_timestamp {
  79.     byte    type;
  80.     byte    code;
  81.     word    checksum;
  82.     word    identifier;
  83.     word    sequence;
  84.     longword    original;    /* original timestamp */
  85.     longword    receive;    /* receive timestamp */
  86.     longword    transmit;    /* transmit timestamp */
  87. };
  88.  
  89. typedef struct icmp_info {
  90.     byte    type;
  91.     byte    code;
  92.     word    checksum;
  93.     word    identifier;
  94.     word    sequence;
  95. };
  96.  
  97. typedef union  {
  98.     struct icmp_unused    unused;
  99.     struct icmp_pointer    pointer;
  100.     struct icmp_ip        ip;
  101.     struct icmp_echo    echo;
  102.     struct icmp_timestamp    timestamp;
  103.     struct icmp_info    info;
  104. } icmp_pkt;
  105.  
  106. typedef struct pkt {
  107.     in_Header     in;
  108.     icmp_pkt     icmp;
  109.     in_Header    data;
  110. };
  111.  
  112. static word icmp_id = 0;
  113.  
  114. static longword ping_hcache = 0L;    /* host */
  115. static longword ping_tcache = 0L;    /* time */
  116. static longword ping_number = 0L;
  117. extern    word debug_on;
  118. extern    word sourcequench;        /* non-zero if rcv'd ICMP S. Q. */
  119.  
  120. void
  121. icmp_init()                /* reinit all local statics */
  122. {
  123.     ping_hcache = ping_tcache = ping_number = 0L;
  124.     icmp_id = 0;
  125.     return;
  126. }
  127.  
  128. longword 
  129. chk_ping(longword host, longword *ptr)
  130. {
  131.     if ((ping_hcache == host) && (ptr != NULL))
  132.         {
  133.         ping_hcache = 0xffffffffL;
  134.         *ptr = ping_number;
  135.         return (ping_tcache);
  136.         }
  137.     return (0xffffffffL);
  138. }
  139.  
  140. void
  141. icmp_print(byte *msg)
  142. {
  143.     if (msg == NULL) return;
  144.     outs("\n\r ICMP: ");
  145.     outs(msg);
  146. }
  147.  
  148. struct pkt *
  149. icmp_Format(longword destip)
  150. {
  151.     eth_address dest;
  152.  
  153.         /* we use arp rather than supplied hardware address */
  154.         /* after first ping this will still be in cache */
  155.  
  156.     if (arp_resolve(destip, dest) == 0)
  157.         return (NULL);            /* unable to find address */
  158.     return ((struct pkt*)eth_formatpacket(dest, 8));
  159. }
  160. /*
  161.  * icmp_Reply - format a reply packet
  162.  *            - note that src and dest are NETWORK order not host!!!!
  163.  */
  164. int
  165. icmp_Reply(struct pkt *p, longword src, longword dest, int icmp_length)
  166. {
  167.  
  168.     if (p == NULL) return (0);        /* failure */
  169.  
  170.     /* finish the icmp checksum portion */
  171.     p->icmp.unused.checksum = 0;
  172.     p->icmp.unused.checksum = ~checksum(&p->icmp, icmp_length);
  173.  
  174.     /* encapsulate into a nice IP packet */
  175.     p->in.hdrlen_ver = 0x45;
  176.     p->in.length = intel16(sizeof(in_Header) + icmp_length);
  177.     p->in.tos = 0;
  178.     p->in.identification = intel16(icmp_id++);    /* not using IP id */
  179.     p->in.frag = 0;
  180.     p->in.ttl = 250;
  181.     p->in.proto = ICMP_PROTO;
  182.     p->in.checksum = 0;
  183.     p->in.source = src;
  184.     p->in.destination = dest;
  185.     p->in.checksum = ~checksum(&p->in, sizeof(in_Header));
  186.  
  187.     return (eth_send(intel16(p->in.length)));    /* send the reply */
  188. }
  189. int
  190. icmp_handler(in_Header *ip)
  191. {
  192.     register icmp_pkt *icmp, *newicmp;
  193.     struct pkt *pkt;
  194.     int len, code;
  195.     in_Header *ret;
  196.  
  197.     len = in_GetHdrlenBytes(ip);
  198.     icmp = (icmp_pkt *)((byte *)ip + len);
  199.     len = intel16(ip->length) - len;
  200.     if (checksum(icmp, len) != 0xffff)
  201.         return (0);                /* 0 = failure */
  202.  
  203.     code = icmp->unused.code;
  204.     switch (icmp->unused.type)
  205.     {
  206.     case 0:             /* icmp echo reply received */
  207. /*         icmp_print("received icmp echo receipt"); */
  208.  
  209.         /* check if we were waiting for it */
  210.         ping_hcache = intel(ip->source);
  211.         ping_tcache = set_timeout(1) -
  212.             *(longword *)(&icmp->echo.identifier);
  213.         if (ping_tcache > 0xffffffffL)
  214.             ping_tcache += 0x1800b0L;
  215.  
  216.         ping_number =
  217.             *(longword*)(((byte*)(&icmp->echo.identifier)) + 4);
  218.                         /* do more */
  219.         break;
  220.  
  221.     case 3 : /* destination unreachable message */
  222.         if (code < 6)
  223.             {
  224.             icmp_print(unreach[code]);
  225.  
  226.              /* handle udp or tcp socket */
  227.             ret = (in_Header *)(icmp) + sizeof(icmp_pkt);
  228.             if (ret->proto == TCP_PROTO)
  229.                 tcp_cancel(ret);
  230.             if (ret->proto == UDP_PROTO)
  231.                 udp_cancel(ret);
  232.             }
  233.         break;
  234.  
  235.     case 4:                /* source quench */
  236. /*        icmp_print("Source Quench"); */
  237.         sourcequench = 1;    /* set flag, used in TCP code */
  238.         break;
  239.  
  240.     case 5:                 /* redirect */
  241.         if (code < 4)
  242.             {
  243.             arp_register(intel(icmp->ip.ipaddr),
  244.                 intel(icmp->ip.ip.destination));
  245.  
  246.             icmp_print(redirect[code]);
  247.             }
  248.         break;
  249.  
  250.     case 8: /* icmp echo request */
  251. /*         icmp_print("PING requested of us"); */
  252.  
  253.         /* do arp and create packet */
  254.             /* format the packet with the request's hardware address */
  255.         pkt = (struct pkt*)(eth_formatpacket(
  256.                 (eth_address *)eth_hardware(ip), 8));
  257.         newicmp = &pkt->icmp;
  258.         bcopy(icmp, newicmp, len);
  259.         newicmp->echo.type = 0;
  260.         newicmp->echo.code = code;
  261.  
  262.         /* use supplied ip values in case we ever multi-home */
  263.         /* note that ip values are still in network order */
  264.         icmp_Reply(pkt, ip->destination, ip->source, len);
  265.  
  266. /*         icmp_print("PING reply sent"); */
  267.  
  268.         break;
  269.  
  270.     case 11:             /* time exceeded message */
  271.         if (code < 2)
  272.             icmp_print(exceed[code]);
  273.         break;
  274.  
  275.     case 12:             /* parameter problem message */
  276.         icmp_print("IP Parameter problem");
  277.         break;
  278.  
  279.     case 13:             /* timestamp message */
  280. /*        icmp_print("Timestamp message"); */
  281.         /* send reply */
  282.         break;
  283.  
  284.     case 14:             /* timestamp reply */
  285. /*        icmp_print("Timestamp reply"); */
  286.         /* should store */
  287.         break;
  288.  
  289.     case 15:             /* info request */
  290. /*        icmp_print("Info requested"); */
  291.         /* send reply */
  292.         break;
  293.  
  294.     case 16:             /* info reply */
  295. /*        icmp_print("Info reply"); */
  296.         break;
  297.     }                /* end of switch */
  298.     return (1);            /* status of success */
  299. }
  300.  
  301.